package com.ruoyi.dj.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Tuple;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.ruoyi.common.config.props.AllPathProperties;
import com.ruoyi.common.constant.TableConstants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.domain.vo.DensVO;
import com.ruoyi.common.exception.ProcessStopException;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.*;
import com.ruoyi.common.utils.biz.BizModule;
import com.ruoyi.common.utils.biz.CommonUtil;
import com.ruoyi.common.utils.biz.PathUtil;
import com.ruoyi.dj.domain.GlobalDensitySimulateFutureParam;
import com.ruoyi.dj.domain.GlobalDensitySimulateNewParam;
import com.ruoyi.dj.domain.GlobalDensitySimulateParam;
import com.ruoyi.dj.mapper.AtmDensityCalculationMapper;
import com.ruoyi.dj.service.AtmDensityCalculationService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import javax.annotation.Resource;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
@Slf4j
public class AtmDensityCalculationServiceImpl implements AtmDensityCalculationService {

    @Autowired
    private AllPathProperties allPath;
    @Resource
    AtmDensityCalculationMapper atmDensityCalculationMapper;


    @Override
    public AjaxResult getGlobalTatestTime() {
        String F107Time = atmDensityCalculationMapper.getGlobalTatestTime(TableConstants.F107);
        List<Date> listDate = new ArrayList<>();
        listDate.add(DateUtils.convertString2Date("yyyy-MM-dd HH:mm:ss",F107Time));
        String KPTime = atmDensityCalculationMapper.getGlobalTatestTime(TableConstants.Kp);
        listDate.add(DateUtils.convertString2Date("yyyy-MM-dd HH:mm:ss",KPTime));
        String APTime = atmDensityCalculationMapper.getGlobalTatestTime(TableConstants.Ap);
        listDate.add(DateUtils.convertString2Date("yyyy-MM-dd HH:mm:ss",APTime));
        Collections.sort(listDate, (d1, d2) -> d1.compareTo(d2));
        return AjaxResult.success("获取成功！",listDate.get(0));
    }


    @Override
    public AjaxResult getGlobalHistDataNew(GlobalDensitySimulateNewParam param) throws ProcessStopException {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        String sseid = param.getSseId() + loginUser.getUsername();
        Date startDate = param.getTime();
        Date endDate = param.getEndTime();
        int days = (int)DateUtil.betweenDay(startDate, endDate, true)+1;
        List<FutureTask<AjaxResult>> tasks = new ArrayList<>();

        ExecutorService executorService = Executors.newFixedThreadPool(5);

        AtomicInteger atomicInteger = new AtomicInteger(0);
        for (int i = 0; i < days; i++) {
            DateTime time = DateUtil.offset(startDate, DateField.DAY_OF_MONTH, i);
            time.setField(DateField.HOUR_OF_DAY,param.getIndex());
            GlobalDensitySimulateParam oldParam = new GlobalDensitySimulateParam();
            String format = DateUtil.format(time, "yyyy-MM-dd HH:mm:ss");
            BeanUtils.copyProperties(param,oldParam);
            oldParam.setTime(format);
            oldParam.setSseId(sseid);
            //组装以调用旧的逻辑
            FutureTask<AjaxResult> task = new FutureTask<>(() -> {
                AjaxResult globalHistData = getGlobalHistData(oldParam);
                //输出进度
                int andAdd = atomicInteger.getAndIncrement();
                SseEmitterUtils.sendMessage(sseid,String.format("%d",andAdd*100/days));
                return globalHistData;
            });
            executorService.execute(task);
            tasks.add(task);
        }

        ServiceException throwable = null;
        List<Object> list = new ArrayList<>();
        for (int i = 0; i < tasks.size(); i++) {
            FutureTask<AjaxResult> task = tasks.get(i);
            try {
                AjaxResult result = task.get(30, TimeUnit.MINUTES);
                list.add(result.get("data"));
            }catch (Exception e) {
                log.error("",e);
                if (e.getCause().getClass() == ProcessStopException.class) {
                    executorService.shutdownNow();
                    throw new ProcessStopException(e.getMessage());
                } else if (e.getCause().getClass() == ServiceException.class) {
                    throwable = (ServiceException) e.getCause();
                }
                //ignore
            }
        }
        if (list.isEmpty() && throwable!= null){
            throw throwable;
        }
        SseEmitterUtils.sendMessage(sseid,"100");
        SseEmitterUtils.remove(sseid);
        executorService.shutdown();
        return AjaxResult.success("获取成功！",list);
    }

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public List<Date> densTimeRange(String type) {
        //先查询数据库最新数据
        String tableName = "";
        if ("future".equals(type)) {
            // 最大观测时间 和  最大预报时间
            tableName ="SWDATA_OBS_F107";
            Date end = jdbcTemplate.queryForObject("select max(\"DATETIME\") FROM SWDATA_FUTURE_F107" , Date.class);
            Date start = jdbcTemplate.queryForObject("select max(\"DATETIME\") FROM SWDATA_OBS_F107" , Date.class);
            end = DateUtil.offset(end, DateField.DAY_OF_MONTH, -81);
            return ListUtil.of(start,end);
        }else {
            //历史数据,最大最小观测时间
            tableName ="SWDATA_OBS_F107";
            Date max = jdbcTemplate.queryForObject("select max(\"DATETIME\") FROM "+tableName , Date.class);
            Date min = jdbcTemplate.queryForObject("select min(\"DATETIME\") FROM " +tableName , Date.class);
            DateTime start = DateUtil.offset(min, DateField.DAY_OF_MONTH, +81);
            DateTime end = DateUtil.offset(max, DateField.DAY_OF_MONTH, -81);
            return ListUtil.of(start,end);
        }

    }

    @Override
    public List<Date> outTimeRange() {
        //  * 观测最小时间+81  --   观测最大时间-81天
        Date maxDate = jdbcTemplate.queryForObject("select max(\"DATETIME\") FROM SWDATA_OBS_F107" , Date.class);
        Date minDate = jdbcTemplate.queryForObject("select min(\"DATETIME\") FROM SWDATA_OBS_F107" , Date.class);
        DateTime start = DateUtil.offset(minDate, DateField.DAY_OF_MONTH, +81);
        DateTime end = DateUtil.offset(maxDate, DateField.DAY_OF_MONTH, -81);
        return ListUtil.of(start,end);
    }


    @Override
    public AjaxResult getGlobalHistData(GlobalDensitySimulateParam param) throws ProcessStopException {
        Map<String, Object> resMap = new HashMap<>();
        //首先按照该参数进行数据查询如果数据已经存在则不进行算法调用
        String path = atmDensityCalculationMapper.getGlobalHistData(param);
        if (!StringUtils.isBlank(path)){
            Map<String, Object> map = new HashMap<>();
            map.put("path", path);
            String name = new File(path).getName();
            String[] split = name.split("_");
            String format = DateUtil.format(DateUtil.parse(split[1], "yyyy-MM-dd-HH-mm-ss"), "yyyy-MM-dd HH:mm:ss");
            String element = "";
            if (split[5].split("\\.")[0].equals("dens")){
                element = "密度";
            }else {
                element = "温度";
            }
            StringBuilder builder = new StringBuilder();
            builder.append(split[0]).append("模型 ").append(format).append(" ").append(split[2]).append(" 高度下全球大气").append(element).append("分布图");
            resMap.put("title",builder.toString());
            return AjaxResult.success("获取成功！",map);
        }
        //判断是否为Tc模型
        if (param.getModel().equalsIgnoreCase("TIEGCM")){

            String codePath = PathUtil.codeModuleDir(BizModule.MODEL_CAL) + PathUtil.moduleDirs().getModelCal().get("tc_picture");

            List<String> commandList = new ArrayList<>();
            commandList.add("python");
            commandList.add("-u");
            commandList.add(codePath);
            commandList.add(param.getTime().replaceAll(" ","-"));
            commandList.add(param.getAltitude()+"");
            String resolution = param.getResolution().split("x")[0];
            if (!resolution.contains(".")){
                resolution +=".0";
            }
            commandList.add(resolution);
            String results = ExecUtil.execPythonNoSendSse(commandList, param.getSseId());
            System.out.println(results);
            results = results.split("###")[1];
            results = results.replaceAll("\n","");
            resMap.put("path", results);
            return AjaxResult.success("获取成功!", resMap);
        }
        List<String> commandList = new ArrayList<>();
        commandList.add("python");
        commandList.add("-u");

        String pythonPath = allPath.getRootPath().getBase()
                + allPath.getRootPath().getPathCode()
                + allPath.getModuleDir().getModelCal().get("dir")
                + allPath.getModuleDir().getModelCal().get("densityGlobal");

        commandList.add(pythonPath);
        commandList.add(param.getTime().replaceAll(" ","-"));
        commandList.add(param.getAltitude()+"");
        String[] resolution = param.getResolution().split("x");
        commandList.add(resolution[0]);
        commandList.add(resolution[1]);
        commandList.add(param.getElement());
        commandList.add(param.getModel());
        commandList.add(allPath.getRootPath().getBase() + allPath.getRootPath().getPathTmp() + allPath.getModuleDir().getModelCal().get("dir"));
//        String command = "python "+densityGlobalPath+densityGlobalName+" '"+param.getTime()+"' "+param.getAltitude()+" "+param.getResolution().replaceAll("x"," ")+" '"+param.getElement()+"' '"+param.getModel()+"'";
//        String command = "python "+densityGlobalPath+densityGlobalName+" "+param.getTime().replaceAll(" ","-")+" "+param.getAltitude()+" "+param.getResolution().replaceAll("x"," ")+" "+param.getElement()+" "+param.getModel();
        //调用python程序
        String results = ExecUtil.execPythonNoSendSse(commandList, param.getSseId());
        log.info("exec python. commandList:{},results:{}",CollectionUtil.join(commandList, " "),results);
        if (!results.contains("###")){
            throw new ServiceException("算法执行异常" + results);
        }
        results = results.split("###")[1];
        results = results.replaceAll("\n","");
        String name = new File(results).getName();
        String[] split = name.split("_");
        String format = DateUtil.format(DateUtil.parse(split[1], "yyyy-MM-dd-HH-mm-ss"), "yyyy-MM-dd HH:mm:ss");
        String element = "";
        if (split[5].split("\\.")[0].equals("dens")){
            element = "密度";
        }else {
            element = "温度";
        }
        StringBuilder builder = new StringBuilder();
        builder.append(split[0]).append("模型 ").append(format).append(" ").append(split[2]).append(" 高度下全球大气").append(element).append("分布图");
        resMap.put("title",builder.toString());
        resMap.put("path", results);
        return AjaxResult.success("获取成功！",resMap);
    }

    @Override
    public AjaxResult getOrbitSimulateHist(String satName, String startTime, String endTime, String element, String model, Integer interval, String resolution, String sseId) throws ProcessStopException {
        log.info("start cal");
        LoginUser loginUser = SecurityUtils.getLoginUser();
        sseId+=loginUser.getUsername();
        //判断是否为Tc模型
        if (model.equalsIgnoreCase("TIEGCM")){
            //按照全闭合区间获取数据
            List<Map<String, Object>> list = atmDensityCalculationMapper.getSatelliteData1(satName,startTime,endTime);
            Map<String, Object> map = getCommand(startTime,element,model,list);
            List<String> commandList = (List<String>) map.get("command");
            commandList.add("5.0"); //2024-6-26 程雪要求写死5.0
            System.out.println(commandList.get(0)+" "+commandList.get(1)+" "+commandList.get(2)+" "+commandList.get(3)+" "+commandList.get(4));
            String results = ExecUtil.execPython(commandList,sseId);
            System.out.println(results);
            results = results.split("###")[1];
            Map<String, Object> resMap = readFile(results);
            //删除文件
            deleteFile(map.get("filePath")+"");
            SseEmitterUtils.remove(sseId);
            return AjaxResult.success("获取成功！", resMap.get(resMap.get("time")));
        }
        //计算是否需要进行多线程处理，如果时间跨度大于一小时则进行多线程处理，最多开辟12个线程
        Date start = DateUtils.convertString2Date("yyyy-MM-dd HH:mm:ss",startTime);
        Date end = DateUtils.convertString2Date("yyyy-MM-dd HH:mm:ss",endTime);
        assert end != null;
        assert start != null;
        long duration = end.getTime()-start.getTime();
        int hours = (int)Math.ceil((double) duration/3600000d);
        //获取所有时间间隔
        List<String> timeList = new ArrayList<>();
        timeList.add(startTime);
        Date date = start;
        for (int i=0;i<=hours;i++){
            if (date.before(end)&&hours>0){
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(date);
                calendar.add(Calendar.HOUR_OF_DAY, 1);
                date = calendar.getTime();
                if (date.after(end)){
                    timeList.add(endTime);
                }else {
                    timeList.add(DateUtils.convertDate2String("yyyy-MM-dd HH:mm:ss",date));
                }
            }
        }
        //判断是否需要多线程处理
        //如果时间跨度小于等于1小时则不需要执行多线程进行数据处理
        List<String> pathList = new ArrayList<>();
        List<Map<String, Object>> lists = new ArrayList<>();
        if (timeList.size()==2) {
            //按照全闭合区间获取数据
            List<Map<String, Object>> listOne  = atmDensityCalculationMapper.getSatelliteData1(satName,timeList.get(0),timeList.get(1));
            //拼装python命令
            Map<String,Object> map = getCommand(timeList.get(0),element,model,listOne);
            String results = ExecUtil.execPython((List<String>) map.get("command"),sseId);
            results = results.split("###")[1];
            System.out.println(results);
            pathList.add(results);
            Map<String, Object> resMap = readFile(results);
            //删除文件
            deleteFile(map.get("filePath")+"");
            SseEmitterUtils.remove(sseId);
            return AjaxResult.success("获取成功！", resMap.get(resMap.get("time")));
        }else {
            //先进行一个时间跨度耗时计算
            LocalDateTime begin = LocalDateTime.now();
            //按照全闭合区间获取数据
            //List<Map<String, Object>> list1 = atmDensityCalculationMapper.getSatelliteData1(satName,timeList.get(0),timeList.get(1));
//            String command = "python"+" -u "+orbitSimulatePath+orbitSimulateName+" "+orbitOutPath+matcher.replaceAll("")+".txt"+" "+element+" "+model;
            //拼装python命令
            //Map<String,Object> map = getCommand(timeList.get(0),element,model,list1);
            //String results = ExecUtil.execPython1((List<String>) map.get("command"), sseId);
            //results = results.split("###")[1];
//            System.out.println("第一次执行"+LocalDateTime.now());
            //删除文件
            //deleteFile(map.get("filePath")+"");
            //lists.add(readFile(results));
            //pathList.add(results);
            LocalDateTime ends = LocalDateTime.now();
            ExecutorService executorService = Executors.newFixedThreadPool(10);
            List<Future> futures = new ArrayList<>();
            //timeList.subList(0,1).clear();
            String ssId = sseId;
            AtomicInteger setNum = new AtomicInteger(0);
            for (int i = 0; i < timeList.size(); i++) {
                int num = i;
                FutureTask task = new FutureTask(new Callable(){

                    @Override
                    public String call() throws ProcessStopException {
                        Map<String,Object> mapT;
                        //按照左开右闭规则获取数据
                        List<Map<String, Object>> list = atmDensityCalculationMapper.getSatelliteData(satName,timeList.get(num),timeList.get(num+1));
                        //给调用python 命令中加上参数（-u）代表-u代表不通过缓存，直接输出,或者python代码print 结束后执行刷新缓冲区操作sys.stdout.flush()
                        mapT = getCommand(timeList.get(num),element,model,list);
                        String resultss = null;
                        resultss = ExecUtil.execPythonNoSendSse((List<String>) mapT.get("command"), ssId);
                        //删除文件
                        deleteFile(mapT.get("filePath")+"");
                        if(StrUtil.isNotEmpty(resultss)){
                            resultss = resultss.split("###")[1];
                            pathList.add(resultss);
                            lists.add(readFile(resultss));
                            log.info("------------------add list-----------------------");
                        }
                        //输出进度
                        int step = setNum.addAndGet(1);
                        int rate = (int)(step*100/timeList.size());
                        SseEmitterUtils.sendMessage(ssId,rate+"");
                        return "";
                    }
                });
                futures.add(task);
                executorService.execute(task);
            }

            for (Future future : futures) {
                try {
                    future.get(20,TimeUnit.MINUTES);
                } catch (Exception e) {
                    log.error("",e);
                    if (e.getCause().getClass() ==ProcessStopException.class ) {
                        executorService.shutdownNow();
                        throw new ProcessStopException("动态修正系数计算评估已终止");
                    }
                }
            }
        }
        //按顺序进行数据拼接
        lists.sort(Comparator.comparing(a -> (Long.valueOf(a.get("time") + ""))));
//        System.out.println(JSON.toJSONString(lists.get(0)));
        List<String> tiList = new ArrayList<>();
        List<Object> lonList = new ArrayList<>();
        List<Object> latList = new ArrayList<>();
        List<Object> altList = new ArrayList<>();
        List<Object> densList = new ArrayList<>();
        for (Map<String, Object> mp : lists ) {
            tiList.addAll((List<String>) ((Map)mp.get(mp.get("time"))).get("time"));
            lonList.addAll((List<Double>) ((Map)mp.get(mp.get("time"))).get("lon"));
            latList.addAll((List<Double>) ((Map)mp.get(mp.get("time"))).get("lat"));
            altList.addAll((List<Double>) ((Map)mp.get(mp.get("time"))).get("alt"));
            densList.addAll((List<Double>) ((Map)mp.get(mp.get("time"))).get("density"));
        }
        Map<String, Object> reMap = new HashMap<>();
        reMap.put("time",tiList);
        reMap.put("lon",lonList);
        reMap.put("lat",latList);
        reMap.put("alt",altList);
        reMap.put("density",densList);
        reMap.put("pathList", pathList);
        //关闭连接
        SseEmitterUtils.remove(sseId);
        return AjaxResult.success("获取成功！", reMap);
    }
    @Override
    public AjaxResult slideAvg(List<String> pathList) {
        String codePath = PathUtil.codeModuleDir(BizModule.MODEL_CAL)  + PathUtil.moduleDirs().getModelCal().get("slideAvg");
        String tmpPath = PathUtil.tmpModuleDir(BizModule.MODEL_CAL);
        //1.每个path一个线程去调用python，获取结果文件的内容并收集在一起
        List<String> allDataList = Collections.synchronizedList(new ArrayList<>());
        List<CompletableFuture<Void>> allFutures = pathList.stream().map(txtPath -> {
            return CompletableFuture.runAsync(() -> {
                String command = "python " + codePath + " " + txtPath + " 3 " + tmpPath; //窗口大小为3
                String results = ExecUtil.execCmdWithResult(command);
                String filePath = results.split("###")[1].trim();
                List<String> fileData = CommonUtil.readLineDataByStart(new File(filePath), 2, null);
                allDataList.addAll(fileData);
            });
        }).collect(Collectors.toList());

        //2.对结果排序，再组装成前端需要的格式
        String delimeter = "______";
        CompletableFuture.allOf(allFutures.toArray(new CompletableFuture[allFutures.size()])).join();
        List<Tuple> tuples = allDataList.stream().map(line -> {
                    String[] split = line.split(","); //2002-04-04 00:50:02,145.959,-57.271,518.16634,1.63e-12
                    return split[0] + delimeter + split[4];
                })
                .sorted()
                .map(timeAndDensity -> {
                    String[] split = timeAndDensity.split(delimeter);
                    return new Tuple(split[0], split[1]);
                }).
                collect(Collectors.toList());
        Map<String, Object> resultMap = MapUtil.builder(new HashMap<String, Object>())
                .put("x", tuples.stream().map(o -> o.get(0)).collect(Collectors.toList()))
                .put("y", tuples.stream().map(o -> o.get(1)).collect(Collectors.toList()))
                .build();
        return AjaxResult.success("",resultMap);
    }


    @Override
    public List<DensVO> futureCal(GlobalDensitySimulateFutureParam param) throws ServiceException, ProcessStopException {
        String  script = allPath.getRootPath().getBase()
                + allPath.getRootPath().getPathCode()
                + allPath.getModuleDir().getModelCal().get("dir")
                + allPath.getModuleDir().getModelCal().get("futureCal");
        String outPath = PathUtil.tmpModuleDir(BizModule.MODEL_CAL) + "/futureCal";
        String[] split = param.getResolution().split("[°|x]+");
        String latGap = split[1];
        String lonGap = split[0];
        String method ="";
        switch (param.getMethod()) {
            case "memory":method="长短时记忆神经网络模型";break;
            case "back":method="54阶自回归模型";break;
            case "mult":method="多元线性回归模型";break;
            default:
        }
        List<List> commonds = new ArrayList<>();

        //创建线程池
        ExecutorService executor = Executors.newFixedThreadPool(5);
        //将时间拆成多个天,调用多线程
        //结果返回多个图片,页面轮播
        int days = (int)DateUtil.betweenDay(param.getStartTime(), param.getEndTime(), true);

        //返回进度
        AtomicInteger atomicInteger = new AtomicInteger(0);
        if (days>9) {
            throw new ServiceException("请勿超过10天");
        }
        List<FutureTask<DensVO>> tasks = new ArrayList<>(days);
        for (int i = 0; i <= days; i++) {
            DateTime offset = DateUtil.offset(param.getStartTime(), DateField.DAY_OF_MONTH, i);
            //年月日时
            String dateStr = DateUtil.format(offset, "yyyy-MM-dd")+"-"+param.getIndex()+":00:00";
            List<String> commond = new ArrayList<>();
            commond.add("python");
            commond.add("-u");
            commond.add(script);
            commond.add(dateStr);
            commond.add(param.getAltitude());
            commond.add(latGap);
            commond.add(lonGap);
            commond.add(param.getElement());
            commond.add(param.getModel());
            commond.add(outPath);
            commond.add(method);
            commonds.add(commond);
        }
        LoginUser loginUser = SecurityUtils.getLoginUser();
        String sseId = param.getSseId()+loginUser.getUsername();
        for (int i = 0; i < commonds.size(); i++) {
            List<String> args = commonds.get(i);

            FutureTask<DensVO> task = new FutureTask(()->{
                List<String> resLines = ExecUtil.execPythonZw(args, sseId);
                String res = null;
                for (String resLine : resLines) {
                    if (resLine.startsWith("###")){
                    }else {
                        //结果
                        res = resLine;
                        log.info("模拟结果：{}",res);
                    }
                }
                log.info("开始模拟：{}",args);
                DensVO commonVO = new DensVO();
                int now = atomicInteger.getAndIncrement();
                SseEmitterUtils.sendMessage(sseId,String.format("%d",now*100/days));
                commonVO.setPath(res);
                commonVO.setTitle(new File(res).getName());
                return commonVO;
            });
            tasks.add(task);
            executor.execute(task);
        }
        List<DensVO> res = new ArrayList<>();
        for (int i = 0; i < tasks.size(); i++) {
            try {
                DensVO commonVO = tasks.get(i).get(10, TimeUnit.MINUTES);
                res.add(commonVO);
            } catch (Exception e) {
                log.error("异常或超时",e);
                executor.shutdownNow();
                if (e.getCause().getClass() == ProcessStopException.class) {
                    throw new ProcessStopException("计算终止");
                }
            }
        }
        //结束
        SseEmitterUtils.sendMessage(sseId,"100");
        SseEmitterUtils.remove(sseId);
        List<DensVO> resList = res.stream().sorted((a, b) -> {
            return a.getTitle().compareTo(b.getTitle());
        }).collect(Collectors.toList());
        executor.shutdown();
        return resList;
    }


    @Override
    public AjaxResult addGlobalHistData(GlobalDensitySimulateNewParam param) {

        log.info("param: {}", param);

        //TODO param.getPath()现在是tmp路径的，要把它transfer到ouput下，再入库

        //首先判断路径参数是否为空
        if (CollectionUtil.isEmpty(param.getPath())) {
            return AjaxResult.warn("请等待图片生成后再进行入库保存！");
        }
        //按照该参数进行数据查询如果数据已经存在则不进行入库
        List<DensVO> pngs = param.getPath();
        for (DensVO png : pngs) {
            GlobalDensitySimulateParam oldParam = new GlobalDensitySimulateParam();
            BeanUtils.copyProperties(param,oldParam);
            oldParam.setId(SequenceBuilder.sequenceId());
            ///prod-api/dgdq/tmp/modelCal/Jacchia71_2022-11-29-20-00-00_500.0km_10_10_dens.jpg
            String pngPath = png.getPath().replaceAll("//profilepiesat-dgdq", "/e/piesat-dgdq").replaceAll("/prod-api", "").replaceAll("/dev-api", "");
            String name = new File(pngPath).getName();

            String timeSplit = name.split("_")[1];
            String timeStr = DateUtil.format(DateUtil.parse(timeSplit, "yyyy-MM-dd-HH-mm-ss"), "yyyy-MM-dd HH:mm:ss");
            oldParam.setTime(timeStr);

            oldParam.setPath(pngPath);
            oldParam.setCreateTime(new Date());

            String path = atmDensityCalculationMapper.getGlobalHistData(oldParam);
            if (!StringUtils.isBlank(path)){
                return AjaxResult.success("保存成功！");
            }
            //进行产品文件入库保存
            atmDensityCalculationMapper.addGlobalHistData(oldParam);
        }

        return AjaxResult.success("保存成功！");
    }

    @Override
    public AjaxResult getDensityProfile(String time, String startAlt, String endAlt, Integer interval, Double lon, Double lat, String model) {

        String  pythonPath = allPath.getRootPath().getBase()
                + allPath.getRootPath().getPathCode()
                + allPath.getModuleDir().getModelCal().get("dir")
                + allPath.getModuleDir().getModelCal().get("densityProfile");

        String command = "python "+pythonPath+" "+time.replaceAll(" ","-")+" "+startAlt+" "+endAlt+" "+interval+" "+lon+" "+lat+" '"+model+"'";
        System.out.println(command);
        //调用python程序
        String results = ExecUtil.execCmdWithResult(command);

        results = results.replaceAll("'","\"").replaceAll("\n","").split("###")[1].replaceAll("O2","O₂").replaceAll("N2","N₂");
        //进行Json字符串转换
        Map<String,Object> map = JSON.parseObject(results, Map.class);
//        //进行数据处理
        List<String> valueList = new ArrayList<>();
//        Map<String,Object> map = new HashMap<>();
//        List<String> dd = new ArrayList<>();
//        dd.add("3.96e-5");
//        dd.add("2.04e-26");
//        map.put("Ar",dd);
//        List<String> dd1 = new ArrayList<>();
//        dd.add("3.96e-36");
//        dd.add("2.04e-36");
//        map.put("O₂",dd1);
        List<String> arList = (List)(map.get("Ar"));
        List<String> o2List = (List)(map.get("O₂"));
        List<String> n2List = (List)(map.get("N₂"));
        List<String> hList = (List)(map.get("H"));
        List<String> heList = (List)(map.get("He"));
        List<String> nList = (List)(map.get("N"));
        List<String> oList = (List)(map.get("O"));
        List<String> dList = (List)(map.get("dens"));
        List<String> tempList = (List)(map.get("temp"));
        //valueList.addAll(arList);
        //valueList.addAll(o2List);
        //valueList.addAll(n2List);
        //valueList.addAll(dList);
        //valueList.addAll(hList);
        //valueList.addAll(heList);
        //valueList.addAll(nList);
        //valueList.addAll(oList);
        //List<Integer> indexValue = new ArrayList<>();
        //for (String value : valueList) {
        //    indexValue.add(Integer.valueOf(value.split("e")[1]));
        //}
        ////进行排序
        //indexValue.sort((a, b) -> a - b);
        //Integer unit = indexValue.get(0)+20;
        //map.put("Ar",dealData(arList, unit));
        //map.put("O₂",dealData(o2List, unit));
        //map.put("N₂",dealData(n2List, unit));
        //map.put("dens",dealData(dList, unit));
        //map.put("H",dealData(hList, unit));
        //map.put("He",dealData(heList, unit));
        //map.put("N",dealData(nList, unit));
        //map.put("O",dealData(oList, unit));
        //map.put("unit","e"+unit);
        map.put("unit","");
        //进行最终值添加
        return AjaxResult.success("获取成功！",map);
    }

    @Override
    public SseEmitter push(String id, String flag) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        return SseEmitterUtils.connect(id+loginUser.getUsername(),flag);
                // 超时时间设置为3s，用于演示客户端自动重连
//        SseEmitter sseEmitter = new SseEmitter(0L);
//        // 设置前端的重试时间为1s
//        try {
//            sseEmitter.send(SseEmitter.event().reconnectTime(1000).data("连接成功"));
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//        sseCache.put(id, sseEmitter);
//        System.out.println("add " + id);
//        sseEmitter.onTimeout(() -> {
//            System.out.println(id + "超时");
//            sseCache.remove(id);
//        });
//        sseEmitter.onCompletion(() -> System.out.println("完成！！！"));
//        return sseEmitter;
    }

    @Override
    public AjaxResult getModelList(String startAlt, String endAlt, String startTime, String endTime) {

        String  pythonPath = allPath.getRootPath().getBase()
                + allPath.getRootPath().getPathCode()
                + allPath.getModuleDir().getModelCal().get("dir")
                + allPath.getModuleDir().getModelCal().get("modelList");

        String command = "python "+pythonPath+" "+startAlt+" "+endAlt+" "+endTime.replaceAll(" ","-");
        System.out.println(command);
        //调用python脚本进行模型推荐
        String results = ExecUtil.execCmdWithResult(command);
        List<String> resList = new ArrayList<>();
        results = results.replaceAll("'","\"").replaceAll("\n","");
        if (results.contains(",")){
            resList.addAll(Arrays.asList(results.split(",")));
        }else {
            resList.add(results);
        }
        //调用Tc模型校验算法
        String codePath = PathUtil.codeModuleDir(BizModule.MODEL_CAL) + PathUtil.moduleDirs().getModelCal().get("tc_check");
        command = "python "+codePath+" "+startTime.replaceAll(" ","-")+" "+endTime.replaceAll(" ","-")+" "+startAlt+" "+endAlt;
        System.out.println(command);
        String checkR = ExecUtil.execCmdWithResult(command);
        checkR = checkR.replaceAll("'","\"").replaceAll("\n","");
        if (!StringUtils.isBlank(checkR)){
            resList.add(checkR);
        }
        return AjaxResult.success("获取成功！", resList);
    }

    @Override
    public AjaxResult getTimeRange(String satName) {
//        String tableName = "SWDATA_OBS_DEN_"+satName;
        Map<String, Date> map = atmDensityCalculationMapper.getTimeRange(satName);
        return AjaxResult.success("获取成功！", map);
    }

    @Override
    public AjaxResult getProfileTimeRange() {
        Map<String, Object> map = atmDensityCalculationMapper.getProfileTimeRange();
        return AjaxResult.success("获取成功！", map);
    }

    @Override
    public AjaxResult getModelBySatellite(String startTime, String endTime, String satName) {
        //根据卫星和时间获取高度范围
//        String tableName = "SWDATA_OBS_DEN_"+satName;
        Map<String, Object> map = atmDensityCalculationMapper.getAltRange(satName,startTime,endTime);
        String  pythonPath = allPath.getRootPath().getBase()
                + allPath.getRootPath().getPathCode()
                + allPath.getModuleDir().getModelCal().get("dir")
                + allPath.getModuleDir().getModelCal().get("modelList");

        String command = "python "+pythonPath+" "+map.get("startAlt")+" "+map.get("endAlt")+" "+endTime.replaceAll(" ","-");
        System.out.println(command);
        //调用python脚本进行模型推荐
        String results = ExecUtil.execCmdWithResult(command);
        List<String> resList = new ArrayList<>();
        results = results.replaceAll("'","\"").replaceAll("\n","");
        if (results.contains(",")){
            resList.addAll(Arrays.asList(results.split(",")));
        }else {
            resList.add(results);
        }
        //调用Tc模型校验算法
        String codePath = PathUtil.codeModuleDir(BizModule.MODEL_CAL) + PathUtil.moduleDirs().getModelCal().get("tc_check");
        command = "python "+codePath+" "+startTime.replaceAll(" ","-")+" "+endTime.replaceAll(" ","-")+" "+map.get("startAlt")+" "+map.get("endAlt");
        System.out.println(command);
        String checkR = ExecUtil.execCmdWithResult(command);
        checkR = checkR.replaceAll("'","\"").replaceAll("\n","");
        if (!StringUtils.isBlank(checkR)){
            resList.add(checkR);
        }
        return AjaxResult.success("获取成功！", resList);
    }

    private void writeToFile(String filePath, List<Map<String, Object>> list){
        //判断文件目录是否存在
        File file = new File(filePath);
        if (file.exists()) {
            file.delete();
        }
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
        //将数据写入本地文件
        FileWriter fileWriter = null;
        try {
            fileWriter = new FileWriter(filePath, true);
            StringBuilder stringBuilder = new StringBuilder("time,longitude,latitude,altitude");
            fileWriter.write(stringBuilder.toString());
            fileWriter.write("\n");
            for (Map<String, Object> row : list) {
                StringBuilder sb = new StringBuilder();
                sb.append((row.get("time")+"").substring(0,19)).append(",").append(row.get("lon")).append(",").append(row.get("lat")).append(",").append(row.get("alt"));
                fileWriter.write(sb.toString());
                fileWriter.write("\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (fileWriter != null) {
                try {
                    fileWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public Map<String, Object> readFile(String filePath) {
        //进行文件读取
        Map<String, Object> resMap = new HashMap<>();
        String time = filePath.substring(filePath.lastIndexOf('/') + 1).replaceAll("-","").split("_")[0];
        Map<String, Object> map = new HashMap<>();
        try {
            //进行文件信息添加
            InputStreamReader read = new InputStreamReader(new FileInputStream(filePath), StandardCharsets.UTF_8);
            BufferedReader bufferedReader = new BufferedReader(read);
            String str = null;
            bufferedReader.readLine();
            List<String> timeList = new ArrayList<>();
            List<Object> lonList = new ArrayList<>();
            List<Object> latList = new ArrayList<>();
            List<Object> altList = new ArrayList<>();
            List<Object> densList = new ArrayList<>();
            while ((str = bufferedReader.readLine()) != null){
                String[] args = str.split(",");
                timeList.add(args[0]);
                System.out.println(args[0]);
                lonList.add(Double.valueOf(args[1]));
                latList.add(Double.valueOf(args[2]));
                altList.add(Double.valueOf(args[3]));
                densList.add(Double.valueOf(args[4]));
            }
            map.put("time",timeList);
            map.put("lon",lonList);
            map.put("lat",latList);
            map.put("alt",altList);
            map.put("density",densList);
        } catch (Exception e) {
            e.printStackTrace();
        }
        resMap.put(time,map);
        resMap.put("time",time);
        return resMap;
    }

    public static void deleteFile(String filePath) {
        File file = new File(filePath);
        if (file.exists()) {
            file.delete();
            System.gc();
        }
    }

    /**
     * 获取轨道算法执行命令
     */
    private Map<String,Object> getCommand (String time, String element, String model, List<Map<String, Object>> list){
        Pattern patterns = Pattern.compile(" |:|-");
        Matcher matcher = patterns.matcher(time);
        //针对Tc模型进行特殊处理
        String filePath;
        String pythonPath;
        if (model.equalsIgnoreCase("TIEGCM")){
            filePath = PathUtil.tmpModuleDir(BizModule.MODEL_CAL)+"/" + matcher.replaceAll("")+".txt";
            pythonPath = PathUtil.codeModuleDir(BizModule.MODEL_CAL) + PathUtil.moduleDirs().getModelCal().get("tc_orbit");
        }else {
            String tmpPath =allPath.getRootPath().getBase() + allPath.getRootPath().getPathTmp() + allPath.getModuleDir().getModelCal().get("dir");
            filePath = tmpPath+"/" + matcher.replaceAll("")+".txt";
            pythonPath = allPath.getRootPath().getBase()
                    + allPath.getRootPath().getPathCode()
                    + allPath.getModuleDir().getModelCal().get("dir")
                    + allPath.getModuleDir().getModelCal().get("orbitSimulate");
        }
        //将数据库中查询的数据写入txt文件中
        writeToFile(filePath,list);
        List<String> commands= new ArrayList<>();
        commands.add("python");
        //给调用python 命令中加上参数（-u）代表-u代表不通过缓存，直接输出,或者python代码print 结束后执行刷新缓冲区操作sys.stdout.flush()
        commands.add("-u");
        commands.add(pythonPath);
        commands.add(filePath);
        if (!model.equalsIgnoreCase("TIEGCM")){
            commands.add(element);
            commands.add(model);
            commands.add(allPath.getRootPath().getBase() + allPath.getRootPath().getPathTmp() + allPath.getModuleDir().getModelCal().get("dir"));
        }
        Map<String, Object> map = new HashMap<>();
        map.put("filePath",filePath);
        map.put("command",commands);
        return map;
    }
    private List<String> dealData (List<String> list, Integer num){
        List<String> dataList = new ArrayList<>();
        for (String value : list) {
            String[] arg = value.split("e");
            dataList.add(arg[0]+"e"+(Integer.valueOf(arg[1])-num));
        }
        return dataList;
    }

}
